package com.systar.activity.report;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64;

import com.systar.activity.report.actions.ActionProcessor;
import com.systar.activity.report.actions.ActionType;
import com.systar.activity.report.users.User;
import com.systar.activity.report.users.UserProvider;

public class ActivityReportServlet extends HttpServlet
{
	/**
	 * Serial
	 */
	private static final long serialVersionUID = -4071527759899176097L;

	public static final String authoriseAttribute = "Authorization";

	private ActivityDataPool data;
	private UserProvider userProvider;

	@Override
	public void init() throws ServletException
	{
		// configure data
		data = new ActivityDataPool();
		//data.put("SRC1", new ActivityData("SRC1"));
		//data.put("SRC2", new ActivityData("SRC2"));
		
		// initialize from options contained in context (web.xml) file
		final ServletContext context = getServletContext();
		String zkUrl = context.getInitParameter("zookeeperURL");
		if (zkUrl != null)
		{
			ZookeeperMonitor zkMon = new ZookeeperMonitor(zkUrl, data);
			zkMon.activate();
		}

		// configure users and roles
		try
		{
			userProvider = new UserProvider();
			userProvider.load();
		}
		catch (IOException e)
		{
			throw new ServletException(e);
		}

		System.out.println("Servlet inited");
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		System.out.println("Servlet get");

		processRequest(request, response);
	}

	@Override
	protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
	{
		System.out.println("Servlet post");

		processRequest(request, response);
	}

	private void processRequest(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
	{
		// get Safe parameters 
		Map<RequestParameter, String> parameters = RequestHelper.getRequestParameters(request);
		if (RequestHelper.detectInjections(parameters))
		{
			response.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
		}

		// Get Action from request parameters
		ActionType action = RequestHelper.getAction(parameters);
		if (action == null)
			return;

		// Check authentication
		User authenticatedUser;
		synchronized (request.getSession())
		{
			HttpSession session = request.getSession();
			authenticatedUser = (User) session.getAttribute(authoriseAttribute);
			
			// POST request get login at first connection
			// GET request have to authenticate at each new session or timed out session
			boolean allowLogin = "POST".equals(request.getMethod()) ? true : !session.isNew();
			
			if ((authenticatedUser == null) && allowLogin)
			{
				// Get Authorization header
				String auth = request.getHeader(authoriseAttribute);
				// Do we allow that user?
				authenticatedUser = authenticate(auth);
				// Store in session if succeeded
				if (authenticatedUser != null)
				{
					session.setAttribute(authoriseAttribute, authenticatedUser);
				}
			}
		}
		if (authenticatedUser == null)
		{
			// Not allowed, so report he's unauthorized
			response.setHeader("WWW-Authenticate", "BASIC realm=\"users\"");
			response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			return;
		}

		// Get the action processor
		ActionProcessor processor = action.getProcessor();

		// execute it
		if (processor != null)
			processor.process(request, response, parameters, data);
	}

	// This method checks the user information sent in the Authorization
	// header against the database of users maintained in the users Hashtable.
	protected User authenticate(String auth) throws IOException
	{
		if (auth == null)
			return null; // no auth

		if (!auth.toUpperCase().startsWith("BASIC "))
			return null; // only BASIC authentication

		// Get encoded user and password, comes after "BASIC "
		String userpassEncoded = auth.substring(6);

		// Decode it
		String userpassDecoded = new String(Base64.decodeBase64(userpassEncoded.getBytes()));

		// Check the User provider
		User user = userProvider.searchUser(userpassDecoded);
		return user;
	}
}
